"""
操作步骤追踪模块

提供操作步骤的追踪、记录和管理功能
"""

import time
import uuid
from datetime import datetime
from typing import Dict, List, Optional, Any, Union
from dataclasses import dataclass, field
from enum import Enum
from contextlib import contextmanager

from .logger import get_logger


class StepStatus(Enum):
    """步骤状态枚举"""
    PENDING = "pending"      # 等待执行
    RUNNING = "running"      # 正在执行
    SUCCESS = "success"      # 执行成功
    FAILED = "failed"        # 执行失败
    SKIPPED = "skipped"      # 跳过执行
    CANCELLED = "cancelled"  # 取消执行


@dataclass
class StepInfo:
    """步骤信息"""
    id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
    name: str = ""
    description: str = ""
    status: StepStatus = StepStatus.PENDING
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    duration_ms: Optional[float] = None
    error_message: Optional[str] = None
    metadata: Dict[str, Any] = field(default_factory=dict)
    parent_id: Optional[str] = None
    children: List[str] = field(default_factory=list)
    
    @property
    def is_completed(self) -> bool:
        """是否已完成（成功或失败）"""
        return self.status in [StepStatus.SUCCESS, StepStatus.FAILED, StepStatus.SKIPPED, StepStatus.CANCELLED]
    
    @property
    def is_successful(self) -> bool:
        """是否成功"""
        return self.status == StepStatus.SUCCESS
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "id": self.id,
            "name": self.name,
            "description": self.description,
            "status": self.status.value,
            "start_time": self.start_time.isoformat() if self.start_time else None,
            "end_time": self.end_time.isoformat() if self.end_time else None,
            "duration_ms": self.duration_ms,
            "error_message": self.error_message,
            "metadata": self.metadata,
            "parent_id": self.parent_id,
            "children": self.children
        }


class StepTracker:
    """步骤追踪器"""
    
    def __init__(self, logger_name: Optional[str] = None):
        self.logger = get_logger(logger_name or __name__)
        self.steps: Dict[str, StepInfo] = {}
        self.current_step_stack: List[str] = []
        self.session_id = str(uuid.uuid4())[:8]
        self.session_start_time = datetime.now()
        
        self.logger.info(f"开始新的操作会话: {self.session_id}")
    
    def start_step(
        self,
        name: str,
        description: str = "",
        metadata: Optional[Dict[str, Any]] = None
    ) -> str:
        """
        开始一个新步骤
        
        Args:
            name: 步骤名称
            description: 步骤描述
            metadata: 元数据
            
        Returns:
            str: 步骤ID
        """
        step = StepInfo(
            name=name,
            description=description,
            status=StepStatus.RUNNING,
            start_time=datetime.now(),
            metadata=metadata or {},
            parent_id=self.current_step_stack[-1] if self.current_step_stack else None
        )
        
        self.steps[step.id] = step
        
        # 如果有父步骤，添加到父步骤的子步骤列表
        if step.parent_id:
            parent = self.steps.get(step.parent_id)
            if parent:
                parent.children.append(step.id)
        
        self.current_step_stack.append(step.id)
        
        # 记录日志
        indent = "  " * (len(self.current_step_stack) - 1)
        self.logger.info(f"{indent}▶ 开始步骤: {name}")
        if description:
            self.logger.info(f"{indent}  描述: {description}")
        
        return step.id
    
    def complete_step(
        self,
        step_id: Optional[str] = None,
        status: StepStatus = StepStatus.SUCCESS,
        error_message: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None
    ) -> bool:
        """
        完成步骤
        
        Args:
            step_id: 步骤ID，默认为当前步骤
            status: 完成状态
            error_message: 错误消息
            metadata: 额外元数据
            
        Returns:
            bool: 是否成功完成
        """
        if step_id is None:
            if not self.current_step_stack:
                self.logger.warning("没有正在执行的步骤")
                return False
            step_id = self.current_step_stack[-1]
        
        step = self.steps.get(step_id)
        if not step:
            self.logger.warning(f"步骤不存在: {step_id}")
            return False
        
        # 更新步骤信息
        step.status = status
        step.end_time = datetime.now()
        step.error_message = error_message
        
        if step.start_time:
            step.duration_ms = (step.end_time - step.start_time).total_seconds() * 1000
        
        if metadata:
            step.metadata.update(metadata)
        
        # 从当前步骤栈中移除
        if step_id in self.current_step_stack:
            self.current_step_stack.remove(step_id)
        
        # 记录日志
        indent = "  " * len(self.current_step_stack)
        status_symbol = {
            StepStatus.SUCCESS: "✓",
            StepStatus.FAILED: "✗",
            StepStatus.SKIPPED: "⊘",
            StepStatus.CANCELLED: "⊗"
        }.get(status, "?")
        
        duration_str = f" ({step.duration_ms:.0f}ms)" if step.duration_ms else ""
        self.logger.info(f"{indent}{status_symbol} 步骤完成: {step.name}{duration_str}")
        
        if error_message:
            self.logger.error(f"{indent}  错误: {error_message}")
        
        return status == StepStatus.SUCCESS
    
    def fail_step(
        self,
        error_message: str,
        step_id: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None
    ) -> bool:
        """
        标记步骤失败
        
        Args:
            error_message: 错误消息
            step_id: 步骤ID
            metadata: 额外元数据
            
        Returns:
            bool: 总是返回False
        """
        return self.complete_step(step_id, StepStatus.FAILED, error_message, metadata)
    
    def skip_step(
        self,
        reason: str = "",
        step_id: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None
    ) -> bool:
        """
        跳过步骤
        
        Args:
            reason: 跳过原因
            step_id: 步骤ID
            metadata: 额外元数据
            
        Returns:
            bool: 总是返回True
        """
        if reason:
            metadata = metadata or {}
            metadata["skip_reason"] = reason
        
        self.complete_step(step_id, StepStatus.SKIPPED, None, metadata)
        return True
    
    def get_step(self, step_id: str) -> Optional[StepInfo]:
        """获取步骤信息"""
        return self.steps.get(step_id)
    
    def get_current_step(self) -> Optional[StepInfo]:
        """获取当前步骤"""
        if not self.current_step_stack:
            return None
        return self.steps.get(self.current_step_stack[-1])
    
    def get_root_steps(self) -> List[StepInfo]:
        """获取根步骤列表"""
        return [step for step in self.steps.values() if step.parent_id is None]
    
    def get_step_tree(self, step_id: Optional[str] = None) -> Dict[str, Any]:
        """
        获取步骤树结构
        
        Args:
            step_id: 根步骤ID，默认获取所有根步骤
            
        Returns:
            Dict: 步骤树
        """
        if step_id:
            step = self.steps.get(step_id)
            if not step:
                return {}
            
            tree = step.to_dict()
            tree["children"] = [self.get_step_tree(child_id) for child_id in step.children]
            return tree
        else:
            return {
                "session_id": self.session_id,
                "session_start_time": self.session_start_time.isoformat(),
                "steps": [self.get_step_tree(step.id) for step in self.get_root_steps()]
            }
    
    def get_summary(self) -> Dict[str, Any]:
        """获取执行摘要"""
        total_steps = len(self.steps)
        success_count = sum(1 for step in self.steps.values() if step.status == StepStatus.SUCCESS)
        failed_count = sum(1 for step in self.steps.values() if step.status == StepStatus.FAILED)
        skipped_count = sum(1 for step in self.steps.values() if step.status == StepStatus.SKIPPED)
        running_count = sum(1 for step in self.steps.values() if step.status == StepStatus.RUNNING)
        
        total_duration = sum(
            step.duration_ms for step in self.steps.values() 
            if step.duration_ms is not None
        )
        
        return {
            "session_id": self.session_id,
            "total_steps": total_steps,
            "success_count": success_count,
            "failed_count": failed_count,
            "skipped_count": skipped_count,
            "running_count": running_count,
            "success_rate": success_count / total_steps if total_steps > 0 else 0,
            "total_duration_ms": total_duration,
            "session_duration_ms": (datetime.now() - self.session_start_time).total_seconds() * 1000
        }
    
    def log_summary(self):
        """记录执行摘要"""
        summary = self.get_summary()
        
        self.logger.info("=" * 50)
        self.logger.info(f"操作会话摘要 (ID: {summary['session_id']})")
        self.logger.info(f"总步骤数: {summary['total_steps']}")
        self.logger.info(f"成功: {summary['success_count']}, 失败: {summary['failed_count']}, "
                        f"跳过: {summary['skipped_count']}, 运行中: {summary['running_count']}")
        self.logger.info(f"成功率: {summary['success_rate']:.1%}")
        self.logger.info(f"总耗时: {summary['total_duration_ms']:.0f}ms")
        self.logger.info(f"会话时长: {summary['session_duration_ms']:.0f}ms")
        self.logger.info("=" * 50)
    
    @contextmanager
    def step(
        self,
        name: str,
        description: str = "",
        metadata: Optional[Dict[str, Any]] = None,
        auto_fail_on_exception: bool = True
    ):
        """
        步骤上下文管理器
        
        Args:
            name: 步骤名称
            description: 步骤描述
            metadata: 元数据
            auto_fail_on_exception: 是否在异常时自动标记失败
        """
        step_id = self.start_step(name, description, metadata)
        
        try:
            yield step_id
            self.complete_step(step_id, StepStatus.SUCCESS)
        except Exception as e:
            if auto_fail_on_exception:
                self.fail_step(str(e), step_id)
            raise


# 全局步骤追踪器实例
_global_tracker: Optional[StepTracker] = None


def get_tracker() -> StepTracker:
    """获取全局步骤追踪器"""
    global _global_tracker
    if _global_tracker is None:
        _global_tracker = StepTracker()
    return _global_tracker


def reset_tracker():
    """重置全局步骤追踪器"""
    global _global_tracker
    _global_tracker = None


# 便捷函数
def start_step(name: str, description: str = "", metadata: Optional[Dict[str, Any]] = None) -> str:
    """开始步骤"""
    return get_tracker().start_step(name, description, metadata)


def complete_step(step_id: Optional[str] = None, status: StepStatus = StepStatus.SUCCESS, 
                 error_message: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None) -> bool:
    """完成步骤"""
    return get_tracker().complete_step(step_id, status, error_message, metadata)


def fail_step(error_message: str, step_id: Optional[str] = None, 
             metadata: Optional[Dict[str, Any]] = None) -> bool:
    """失败步骤"""
    return get_tracker().fail_step(error_message, step_id, metadata)


def skip_step(reason: str = "", step_id: Optional[str] = None, 
             metadata: Optional[Dict[str, Any]] = None) -> bool:
    """跳过步骤"""
    return get_tracker().skip_step(reason, step_id, metadata)


def step_context(name: str, description: str = "", metadata: Optional[Dict[str, Any]] = None):
    """步骤上下文管理器"""
    return get_tracker().step(name, description, metadata)